www.gusucode.com > ROCBOSS微社区-微信论坛程序 v2.1PHP源码程序 > ROCBOSS微社区-微信论坛程序 v2.1/ROCBOSS_v2.1.0/ROCBOSS_v2.1.0/system/Engine.php
<?php # 包含ROCPHP框架的核心功能。负责加载HTTP请求,运行已注册的服务,并生成最后的HTTP响应。 namespace system; use system\core\Loader; use system\core\Dispatcher; class Engine { protected $vars; protected $loader; protected $dispatcher; public function __construct() { $this->vars = array(); # Dispatcher负责分发处理函数,Loader负责对象的加载 $this->loader = new Loader(); $this->dispatcher = new Dispatcher(); # 引擎初始化 $this->init(); } # __call是一个魔术方法,当调用一个不存在的函数时,会调用到该函数。动态调用通过此方法执行 public function __call($name, $params) { # 判断是类还是可直接调用的函数 $callback = $this->dispatcher->get($name); # 判断方法或函数是否可以调用,若可以则通过dispatcher处理 if (is_callable($callback)) { return $this->dispatcher->run($name, $params); } # 是否是共享实例 $shared = (!empty($params)) ? (bool) $params[0] : true; # 通过loader加载该类的对象 return $this->loader->load($name, $shared); } # 初始化引擎 public function init() { static $initialized = false; $self = $this; if ($initialized) { $this->vars = array(); $this->loader->reset(); $this->dispatcher->reset(); } # 注册默认组件 $this->loader->register('request', '\system\net\Request'); $this->loader->register('response', '\system\net\Response'); $this->loader->register('router', '\system\net\Router'); $this->loader->register('view', '\system\template\Template'); $this->loader->register('db', '\system\db\DB'); # 注册框架方法 $methods = array( 'start', 'stop', 'route', 'clearRoutes', 'getNowRoute', 'halt', 'error', 'notFound', 'render', 'redirect', 'etag', 'lastModified', 'json', 'jsonp' ); foreach ($methods as $name) { $this->dispatcher->set($name, array($this, '_' . $name)); } # 默认配置 $this->set('root', $this->request()->base); $this->set('handle_errors', true); $this->set('log_errors', false); $initialized = true; } public function handleErrors($enabled) { if ($enabled) { set_error_handler(array($this, 'handleError')); set_exception_handler(array($this, 'handleException')); } else { restore_error_handler(); restore_exception_handler(); } } public function handleError($errno, $errstr, $errfile, $errline) { if ($errno & error_reporting()) { throw new \ErrorException($errstr, $errno, 0, $errfile, $errline); } } public function handleException(\Exception $e) { if ($this->get('log_errors')) { error_log($e->getMessage()); } $this->error($e); } # 映射自定义函数 public function map($name, $callback) { # 不允许映射已经存在的Engine方法 if (method_exists($this, $name)) { throw new \Exception('Cannot override an existing framework method.'); } # 通过dispatcher的set函数将对应的回调函数绑定到一个事件中 $this->dispatcher->set($name, $callback); } # 注册自定义类 public function register($name, $class, array $params = array(), $callback = null) { # 不允许覆盖已经存在的Engine方法 if (method_exists($this, $name)) { throw new \Exception('Cannot override an existing framework method.'); } # 通过loader的register函数进行注册 $this->loader->register($name, $class, $params, $callback); } public function before($name, $callback) { $this->dispatcher->hook($name, 'before', $callback); } public function after($name, $callback) { $this->dispatcher->hook($name, 'after', $callback); } public function get($key = null) { if ($key === null) return $this->vars; return isset($this->vars[$key]) ? $this->vars[$key] : null; } public function set($key, $value = null) { if (is_array($key) || is_object($key)) { foreach ($key as $k => $v) { $this->vars[$k] = $v; } } else { $this->vars[$key] = $value; } } public function has($key) { return isset($this->vars[$key]); } public function clear($key = null) { if (is_null($key)) { $this->vars = array(); } else { unset($this->vars[$key]); } } public function path($dir) { $this->loader->addDirectory($dir); } public function _clearRoutes() { $this->router()->clear(); } public function _getNowRoute() { $request = $this->request(); $router = $this->router(); return $router->route($request)->callback; } # 启动这个框架 public function _start() { $dispatched = false; $self = $this; $request = $this->request(); $response = $this->response(); $router = $this->router(); # 冲刷掉已经存在的输出 if (ob_get_length() > 0) { $response->write(ob_get_clean()); } # 启动输出缓冲 ob_start(); $this->handleErrors($this->get('handle_errors')); # 对AJAX请求关闭缓存 if ($request->ajax) { $response->cache(false); } # 允许后置过滤器的运行 $this->after('start', function() use ($self) { # start完成之后会调用stop()函数 $self->stop(); }); # 对该请求进行路由 while ($route = $router->route($request)) { $params = array_values($route->params); # 是否让路由链继续下去 $continue = $this->dispatcher->execute($route->callback, $params); $dispatched = true; if (!$continue) break; $router->next(); $dispatched = false; } # 路由没找匹配到 if (!$dispatched) { $this->notFound(); } } # 停止框架并且输出当前的响应内容 public function _stop($code = 200) { $this->response()->status($code)->write(ob_get_clean())->send(); } public function _halt($code = 200, $message = '') { $this->response(false)->status($code)->write($message)->send(); } public function _error(\Exception $e) { $msg = sprintf('<h1>500 Internal Server Error</h1>' . '<h3>%s (%s)</h3>' . '<pre>%s</pre>', $e->getMessage(), $e->getCode(), $e->getTraceAsString()); try { $this->response(false)->status(500)->write($msg)->send(); } catch (\Exception $ex) { exit($msg); } } public function _notFound() { $this->response(false)->status(404)->write('<h1>404 Not Found</h1>' . '<h3>The page you have requested could not be found.</h3>' . str_repeat(' ', 512))->send(); } public function _route($pattern, $callback, $pass_route = false) { $this->router()->map($pattern, $callback, $pass_route); } public function _redirect($url, $code = 303) { $base = $this->get('root'); if ($base === null) { $base = $this->request()->base; $this->set('root', $base); } if ($base != '/' && strpos($url, '://') === false) { $url = preg_replace('#/+#', '/', $base . '/' . $url); } $this->response(false)->status($code)->header('Location', $url)->write($url)->send(); } public function _json($data, $code = 200, $encode = true) { $json = ($encode) ? json_encode($data) : $data; $this->response(false)->status($code)->header('Content-Type', 'application/json')->write($json)->send(); } public function _jsonp($data, $param = 'jsonp', $code = 200, $encode = true) { $json = ($encode) ? json_encode($data) : $data; $callback = $this->request()->query[$param]; $this->response(false)->status($code)->header('Content-Type', 'application/javascript')->write($callback . '(' . $json . ');')->send(); } public function _etag($id, $type = 'strong') { $id = (($type === 'weak') ? 'W/' : '') . $id; $this->response()->header('ETag', $id); if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $id) { $this->halt(304); } } public function _lastModified($time) { $this->response()->header('Last-Modified', date(DATE_RFC1123, $time)); if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $time) { $this->halt(304); } } } ?>